bitkeeper revision 1.582.1.1 (3fafbef8y8bKbMkHy5KldiazAvehBA)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 10 Nov 2003 16:38:16 +0000 (16:38 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 10 Nov 2003 16:38:16 +0000 (16:38 +0000)
xen_netwatch.c:
  new file
Makefile:
  New utility for watching network interfaces coming up and going down, and calling a configure script.

.rootkeys
tools/misc/Makefile
tools/misc/xen_netwatch.c [new file with mode: 0644]

index d6cb86def20ae9fbe6d68d399f678f3a0024b69f..930ff03de132900acae1ad1ab3e796938d3fa1ac 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 3f8bcf29ulZIC9rC4wM70H_q4s6VPg tools/misc/xen_log.c
 3f13d81eQ9Vz-h-6RDGFkNR9CRP95g tools/misc/xen_nat_enable
 3f13d81e6Z6806ihYYUw8GVKNkYnuw tools/misc/xen_nat_enable.README
+3fafbef1fJFKCcJLq-ffpauvpM10jQ tools/misc/xen_netwatch.c
 3f1668d4F29Jsw0aC0bJEIkOBiagiQ tools/misc/xen_read_console.c
 3f87ba90EUVPQLVOlFG0sW89BCwouQ tools/misc/xen_refresh_dev.c
 3f72f1bdJPsV3JCnBqs9ddL9tr6D2g xen/COPYING
index c21ae540de5db64efaa38aa8df3b5948345b0edd..1eda792f69df7f7bbc79e7123ad1bf9474ec3871 100644 (file)
@@ -1,13 +1,13 @@
 
-CC       = gcc
-CFLAGS   = -Wall -O3 
-CFLAGS  += -I../../xen/include -I../../xenolinux-sparse/include -I../internal
+CC        = gcc
+CFLAGS    = -Wall -O3 
+EXTRA_INC = -I../../xen/include -I../../xenolinux-sparse/include -I../internal
 
 HDRS     = $(wildcard *.h)
 SRCS     = $(wildcard *.c)
 OBJS     = $(patsubst %.c,%.o,$(SRCS))
 
-TARGETS  = xen_read_console xen_cpuperf xen_refresh_dev
+TARGETS  = xen_read_console xen_cpuperf xen_refresh_dev xen_netwatch
 
 INSTALL  = $(TARGETS) xen-mkdevnodes xen_nat_enable xen-clone 
 
@@ -25,6 +25,9 @@ clean:
        $(RM) *.o $(TARGETS)
        $(MAKE) -C miniterm clean       
 
-%: %.c $(HDRS) Makefile
+xen_netwatch: %: %.c $(HDRS) Makefile
        $(CC) $(CFLAGS) -o $@ $<
 
+%: %.c $(HDRS) Makefile
+       $(CC) $(CFLAGS) $(EXTRA_INC) -o $@ $<
+
diff --git a/tools/misc/xen_netwatch.c b/tools/misc/xen_netwatch.c
new file mode 100644 (file)
index 0000000..b4aac6d
--- /dev/null
@@ -0,0 +1,196 @@
+/******************************************************************************
+ * netwatch.c
+ * 
+ * Watch for network interfaces needing frobbing.
+ * 
+ * Copyright (c) 2003, K A Fraser
+ */
+
+#include <asm/types.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/resource.h>
+#include <sys/time.h>
+#include <sys/un.h>
+#include <sys/wait.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/if.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <time.h>
+
+#define LOG(_f, _a...)                                  \
+    do {                                                \
+        time_t now = time(NULL);                        \
+        char *tstr = ctime(&now);                       \
+        char *p = strchr(tstr, '\n'); if (p) *p = '\0'; \
+        fprintf(logfd, "%s: " _f "\n", tstr,  ## _a);   \
+        fflush(logfd);                                  \
+    } while ( 0 )
+
+#define EXIT do { LOG("Exiting."); return 1; } while ( 0 )
+
+static void daemonise(void)
+{
+    int i;
+    struct rlimit rlim;
+
+    /* Close all file handles we inherited from our parent. */
+    if ( getrlimit(RLIMIT_NOFILE, &rlim) == 0 )
+        for ( i = 0; i < rlim.rlim_cur; i++ )
+            close(i);
+
+    /* Lose the controlling tty. */
+    setsid();
+}
+
+void handle_child_death(int dummy)
+{
+    (void)waitpid(-1, NULL, WNOHANG);
+}
+
+int main(int argc, char **argv)
+{
+    char *logfile = "/var/xen/netwatch";
+    char *scriptfile = "/etc/xen/netwatch";
+    FILE *logfd;
+    int nlfd, unixfd, bytes;
+    int last_index = ~0;
+    unsigned int last_flags = ~0;
+    char buffer[8192];
+    struct sockaddr_nl nladdr;
+    struct nlmsghdr *nlmsg;
+    struct ifinfomsg *ifi;
+    struct ifreq ifr;
+    struct sigaction sigchld;
+
+    /* Ensure that zombie children are reaped. */
+    memset(&sigchld, 0, sizeof(sigchld));
+    sigchld.sa_handler = handle_child_death;
+    sigemptyset(&sigchld.sa_mask);
+    sigchld.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+    (void)sigaction(SIGCHLD, &sigchld, NULL);
+
+    /*
+     * After child daemonises it can't display errors until it opens the log 
+     * file. Since it may be unable to open the log file, we test for that
+     * possibility here.
+     */
+    if ( (logfd = fopen(logfile, "wb")) == NULL )
+    {
+        fprintf(stderr, "Could not open log file '%s' (%d)\n", logfile, errno);
+        fprintf(stderr, "Exiting.\n");
+        return 1;
+    }
+    fclose(logfd);
+
+    switch ( fork() )
+    {
+    case 0:
+        daemonise();
+        break;
+    case -1:
+        fprintf(stderr, "Could not daemonize. (%d)\n", errno);
+        fprintf(stderr, "Exiting.\n");
+        return 1;
+    default:
+        goto out;
+    }
+
+    /* Silent error is forgiveable here, as our parent did a test for us. */
+    if ( (logfd = fopen(logfile, "wb")) == NULL )
+        return 1;
+
+    if ( (nlfd = socket(PF_NETLINK, SOCK_DGRAM, NETLINK_ROUTE)) == -1 )
+    {
+        LOG("Could not open an rtnetlink socket. (%d)\n", errno);
+        EXIT;
+    }
+
+    if ( (unixfd = socket(PF_UNIX, SOCK_DGRAM, 0)) == -1 )
+    {
+        LOG("Could not open UNIX socket. (%d)\n", errno);
+        EXIT;
+    }
+
+    nladdr.nl_family = AF_NETLINK;
+    nladdr.nl_pid    = 0;
+    nladdr.nl_groups = RTMGRP_LINK;
+    if ( bind(nlfd, (struct sockaddr *)&nladdr, sizeof(nladdr)) == -1 )
+    {
+        LOG("Could not bind to kernel (%d)\n", errno);
+        EXIT;
+    }
+
+    for ( ; ; )
+    {
+        memset(buffer, 0, sizeof(buffer));
+
+        if ( (bytes = read(nlfd, buffer, sizeof(buffer))) == -1 )
+        {
+            if ( errno != EINTR )
+                LOG("Error when reading from socket (%d)", errno);
+            continue;
+        }
+
+        if ( bytes == 0 )
+            continue;
+
+        for ( nlmsg = (struct nlmsghdr *)buffer; 
+              !(nlmsg->nlmsg_flags & NLMSG_DONE);
+              nlmsg = NLMSG_NEXT(nlmsg, bytes) )
+        {
+            /* This termination condition works. NLMSG_DONE doesn't always. */
+            if ( nlmsg->nlmsg_len == 0 )
+                break;
+
+            if ( nlmsg->nlmsg_type != RTM_NEWLINK )
+                continue;
+
+            ifi = NLMSG_DATA(nlmsg);
+
+            ifr.ifr_ifindex = ifi->ifi_index;
+            if ( ioctl(unixfd, SIOCGIFNAME, &ifr) == -1 )
+                continue;
+
+            if ( !(ifi->ifi_change & IFF_UP) )
+                continue;
+
+            /* Ignore duplicate messages. */
+            if ( (last_index == ifr.ifr_ifindex) &&
+                 (last_flags == ifi->ifi_flags) )
+                continue;
+            last_index = ifr.ifr_ifindex;
+            last_flags = ifi->ifi_flags;
+
+            LOG("Network %s event for interface %s",
+                (ifi->ifi_flags & IFF_UP) ? "UP" : "DOWN",
+                ifr.ifr_name);
+
+            switch ( fork() )
+            {
+            case 0:
+                execl(scriptfile,
+                      ifr.ifr_name, 
+                      (ifi->ifi_flags & IFF_UP) ? "up" : "down");
+                LOG("Error executing network script '%s %s %s'", 
+                    scriptfile, ifr.ifr_name, 
+                    (ifi->ifi_flags & IFF_UP) ? "up" : "down");
+                return 1;
+            case -1:
+                LOG("Error forking to exec script");
+                break;
+            default:
+                break;
+            }
+        }
+    }
+
+ out:
+    return 0;
+}